package eu.runelord.programmers.t140783;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class App {

	public static void main(String[] args) {
		Node<String> root = new Node<String>("root", null, "ROOT");
		Node<String> firstLvlCh1 = new Node<String>("firstLvlCh1", root,
				"FirstLvlCh1");
		Node<String> firstLvlCh2 = new Node<String>("firstLvlCh2", root,
				"FirstLvlCh2");
		Node<String> secondLvlCh21 = new Node<String>("secondLvlCh21", firstLvlCh2,
		"SecondLvlCh21");
		
		System.out.println(root.getByName("root"));
		System.out.println(root.getByName("root/firstLvlCh1"));
		System.out.println(root.getByName("root/firstLvlCh2"));
		System.out.println(root.getByName("root/firstLvlCh3")); //NULL
		System.out.println(root.getByName("root/firstLvlCh2/secondLvlCh21"));
		Node<?> node = root.getByName("root");
		System.out.println(node.getValue().getClass());
	}
}

class Node<T extends Object> {

	private String name;

	private Node parent;

	private Map<String, Node> children;

	private T value;

	private Class<T> valueClass;

	public Node(String name, Node parent, T value) {
		this.name = name;
		this.parent = parent;
		this.value = value;
		children = new HashMap<String, Node>();
		if (parent != null)
			parent.add(this);
	}

	private void add(Node<T> node) {
		this.children.put(node.name, node);
	}

	public Node getByName(String path) {
		path.replaceFirst("/", "");
		// dla null błąd
		if (path == null)
			throw new NullPointerException("Node path is NULL");

		String elements[] = path.split("/");
		if(elements.length == 1)
			return this;
		String childPath = merge(Arrays.copyOfRange(elements, 2, elements.length));
		Node child = children.get(elements[1]);
		if(child!=null){
			return child.getByName(childPath);
		}
		return null;
	}

	private String merge(String[] childrenPath) {
		String ret = "";
		for (String s : childrenPath)
			ret = ret + "/" + s;
		return ret;
	}

	@Override
	public String toString() {
		return this.value.toString();
	}

	public T getValue() {
		return value;
	}

}
